package nl.weeaboo.sh.io;

import static timon.common.xml.XmlUtil.getBoolean;
import static timon.common.xml.XmlUtil.getInt;
import static timon.common.xml.XmlUtil.getIntAttribute;
import static timon.common.xml.XmlUtil.getString;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nl.weeaboo.sh.Game;
import nl.weeaboo.sh.model.AreaModel;
import nl.weeaboo.sh.model.RoomEnemyModel;
import nl.weeaboo.sh.model.RoomModel;
import nl.weeaboo.sh.model.TileSetIndex;

import org.xml.sax.SAXException;

import timon.common.StringUtil;
import timon.common.xml.XmlElement;
import timon.common.xml.XmlReader;

public class AreaLoader {

	//Functions
	public AreaModel load(String path) throws IOException {
		FileInputStream fin = new FileInputStream(path);
		try {
			return load(null, fin);
		} finally {
			fin.close();
		}
	}
	
	/** The game parameter is optional */
	public AreaModel load(Game game, InputStream in) throws IOException {		
		XmlReader reader = new XmlReader();
		XmlElement root;
		
		try {
			root = reader.read(in);
		} catch (SAXException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw e;
		}	
		
		root = root.getChild("area");
		if (root == null) {
			throw new RuntimeException(String.format("Root node not found (%s)", "area"));
		}
		
		String version = root.getAttribute("version");
		if (version.compareTo("1.0.0") > 0) {
			throw new RuntimeException("Wrong file version: 1.0.0 expected, " + version + " found.");
		}
		
		
		AreaModel area = new AreaModel(root.getAttribute("id"));

		TileSetLoader tileSetLoader = new TileSetLoader();
		for (XmlElement e : root.getChildren("tileSets")) {
			for (XmlElement tileSetE : e.elementChildren()) {
				String path = String.format("tiles/%s.xml", tileSetE.getTextContent().trim());
				if (game != null) {
					area.addTileSet(tileSetLoader.load(area, game.getInputStream(path)));
				} else {
					area.addTileSet(tileSetLoader.load(area, "res/"+path));
				}
			}			
		}
		
		for (XmlElement e : root.elementChildren()) {
			if (!e.getTagName().equals("tileSets")) {
				area.addRoom(parseRoom(area, e));
			}
		}
		
		for (RoomModel room : area.getRooms()) {
			if (room.getId() == null) room.setId(area.generateRoomId());
		}
		return area;
	}
	protected RoomModel parseRoom(AreaModel area, XmlElement e) {
		RoomModel rm = new RoomModel(getString(e, "id"));

		rm.setOffset(getInt(e, "x", 0), getInt(e, "y", 0));
		rm.setSize(getInt(e, "width", 1), getInt(e, "height", 1));
		
		rm.setWallSides(getBoolean(e, "leftWall", false), getBoolean(e, "rightWall", false),
				getBoolean(e, "topWall", false), getBoolean(e, "bottomWall", false));

		rm.setOpenSides(getBoolean(e, "leftOpen", false), getBoolean(e, "rightOpen", false),
				getBoolean(e, "topOpen", false), getBoolean(e, "bottomOpen", false));
		
		XmlElement enemiesE = e.getChild("enemies");
		if (enemiesE != null) {
			for (XmlElement enemyE : enemiesE.getChildren("enemy")) {
				rm.setRoomEnemy(getIntAttribute(enemyE, "x", 0), getIntAttribute(enemyE, "y", 0),
						parseRoomEnemy(enemyE));
			}
		}
		
		for (XmlElement layerE : e.getChildren("layer")) {
			int index = getIntAttribute(layerE, "index", 0);
			
			String lines[] = layerE.getTextContent().split("\\\n");
			for (String line : lines) {
				Pattern p = Pattern.compile("\\((\\d+),(\\d+)\\) ([A-Za-z0-9]\\w+):(\\d+):(\\d+)");
				Matcher m = p.matcher(line);
				if (m.find()) {
					String matches[] = StringUtil.getOuterRegexMatches(m);
					if (matches.length >= 5) {
						TileSetIndex tsi = new TileSetIndex(area.getTileSet(matches[2]),
								Integer.parseInt(matches[3]), Integer.parseInt(matches[4]));
						rm.setTile(index, Integer.parseInt(matches[0]), Integer.parseInt(matches[1]), tsi);
					}
				}
			}			
			
			//TileSetIndex tsi = new TileSetIndex();

			/*for (XmlElement tileE : tilesE.elementChildren()) {
				TileSetIndex tsi = TileSetLoader.parseTileSetIndex(area, tileE);
				rm.setTile(getIntAttribute(tileE, "x", 0), getIntAttribute(tileE, "y", 0), tsi);								
				tsi.dispose();				
			}*/
		}
			
		return rm;
	}	
	
	protected static RoomEnemyModel parseRoomEnemy(XmlElement e) {
		RoomEnemyModel re = new RoomEnemyModel(e.getAttribute("className"));
		return re;
	}
			
	//Getters
	
	//Setters
	
}
